#ifndef _BASIS_VECTOR2_H_
#define _BASIS_VECTOR2_H_

#include <iostream>
#include <cmath>
using namespace std;

class Vector2
{
public:
	Vector2();
	Vector2(float e0, float e1);
	Vector2(const Vector2& v);

	float x() const;
	float y() const;

	const Vector2& operator+() const;
	Vector2 operator-() const;
	float operator[](int i) const;
	float& operator[](int i);

	float length() const;
	float squaredLength() const;

	void makeUnitVector();

	void setX(float _x);
	void setY(float _y);

	float minComponent() const;
	float maxComponent() const;
	float minAbsComponent() const;
	float maxAbsComponent() const;
	int indexOfMinComponent() const;
	int indexOfMinAbsComponent() const;
	int indexOfMaxComponent() const;
	int indexOfMaxAbsComponent() const;

	friend bool operator==(const Vector2& v1, const Vector2& v2);
	friend bool operator!=(const Vector2& v1, const Vector2& v2);

	friend istream &operator>>(istream &is, Vector2 &t);
	friend ostream &operator<<(ostream &os, const Vector2 &t);

	friend Vector2 operator+(const Vector2& v1, const Vector2& v2);
	friend Vector2 operator-(const Vector2& v1, const Vector2& v2);
	friend Vector2 operator/(const Vector2& vec, float scalar);
	friend Vector2 operator*(const Vector2& vec, float scalar);
	friend Vector2 operator*(float scalar, const Vector2& vec);

	Vector2& operator=(const Vector2& v2);
	Vector2& operator+=(const Vector2& v2);
	Vector2& operator-=(const Vector2& v2);
	Vector2& operator*=(const float t);
	Vector2& operator/=(const float t);

	friend Vector2 unitVector(const Vector2& v);
	friend Vector2 minVec(const Vector2& v1, const Vector2& v2);
	friend Vector2 maxVec(const Vector2& v1, const Vector2& v2);
	friend float dot(const Vector2& v1, const Vector2& v2);

protected:

	float e[2];

};

inline Vector2::Vector2(float e0, float e1)
{
	e[0] = e0;
	e[1] = e1;
}

inline const Vector2& Vector2::operator+() const
{
	return *this;
}

inline Vector2 Vector2::operator-() const
{
	return Vector2(-e[0], -e[1]);
}

inline float Vector2::length() const
{
	return sqrt(e[0] * e[0] + e[1] * e[1]);
}

inline float Vector2::squaredLength() const
{
	return e[0] * e[0] + e[1] * e[1];
}

inline void Vector2::makeUnitVector()
{
	*this = (*this) / length();
}

inline float Vector2::minComponent() const
{
	if (e[0] < e[1]) return e[0];
	return e[1];
}

inline float Vector2::maxComponent() const
{
	if (e[0] > e[1]) return e[0];
	return e[1];
}

inline float Vector2::minAbsComponent() const
{
	float temp = fabs(e[0]);
	if (temp > fabs(e[1])) temp = fabs(e[1]);
	return temp;
}

inline float Vector2::maxAbsComponent() const
{
	float temp = fabs(e[0]);
	if (temp < fabs(e[1])) temp = fabs(e[1]);
	return temp;
}

inline int Vector2::indexOfMaxComponent() const
{
	int index = 0;
	if (e[0] < e[1]) 
	{
		index = 1;
	}
	return index;
}

inline int Vector2::indexOfMinComponent() const
{
	int index = 0;
	if (e[0] > e[1])
	{
		index = 1;
	}
	return index;
}

inline int Vector2::indexOfMaxAbsComponent() const
{
	int index = 0;
	if (fabs(e[0]) < fabs(e[1]))
	{
		index = 1;
	}
	return index;
}

inline int Vector2::indexOfMinAbsComponent() const
{
	int index = 0;
	if (fabs(e[0]) > fabs(e[1]))
	{
		index = 1;
	}
	return index;
}

inline bool operator==(const Vector2& v1, const Vector2& v2)
{
	return (v1.e[0] == v2.e[0]) 
		&& (v1.e[1] == v2.e[1]);
}

inline bool operator!=(const Vector2& v1, const Vector2& v2)
{
	return !(v1 == v2);
}

inline Vector2 operator+(const Vector2& v1, const Vector2& v2)
{
	return Vector2(v1.e[0] + v2.e[0], v1.e[1] + v2.e[1]);
}

inline Vector2 operator-(const Vector2& v1, const Vector2& v2)
{
	return Vector2(v1.e[0] - v2.e[0], v1.e[1] - v2.e[1]);
}

inline Vector2 operator/(const Vector2& vec, float scalar)
{
	return Vector2(vec.e[0] / scalar, vec.e[1] / scalar);
}

inline Vector2 operator*(const Vector2& vec, float scalar)
{
	return Vector2(vec.e[0] * scalar, vec.e[1] * scalar);
}

inline Vector2 operator*(float scalar, const Vector2& vec)
{
	return Vector2(vec.e[0] * scalar, vec.e[1] * scalar);
}

inline Vector2& Vector2::operator=(const Vector2& v2)
{
	e[0] = v2.e[0];
	e[1] = v2.e[1];
	return *this;
}

inline Vector2& Vector2::operator+=(const Vector2& v2)
{
	*this = *this + v2;
	return *this;
}

inline Vector2& Vector2::operator-=(const Vector2& v2)
{
	*this = *this - v2;
	return *this;
}

inline Vector2& Vector2::operator*=(const float t)
{
	*this = *this * t;
	return *this;
}

inline Vector2& Vector2::operator/=(const float t)
{
	*this = *this / t;
	return *this;
}

inline Vector2 unitVector(const Vector2& v)
{
	return v / v.length();
}


//	bit-wise min
inline Vector2 minVec(const Vector2& v1, const Vector2& v2)
{
	Vector2 temp(v1);
	if (v1.e[0] > v2.e[0]) temp.setX(v2.e[0]);
	if (v1.e[1] > v2.e[1]) temp.setY(v2.e[1]);
	return temp;
}

//	bit-wise max
inline Vector2 maxVec(const Vector2& v1, const Vector2& v2)
{
	Vector2 temp(v1);
	if (v1.e[0] < v2.e[0]) temp.setX(v2.e[0]);
	if (v1.e[1] < v2.e[1]) temp.setY(v2.e[1]);
	return temp;
}

inline float dot(const Vector2 &v1, const Vector2 &v2)
{
	return v1.e[0] * v2.e[0] + v1.e[1] * v2.e[1];
}






#endif